#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/tcp.h"
#include "lwip/tcpip.h"
#include "lwip/udp.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/init.h"
#include "lwip/timeouts.h"
#include "lwip/netif.h"

#include "ethernetif.h"
#include "netconf.h"

__lwip_dev g_lwipdev;		//lwip控制结构体
struct netif g_lwip_netif;	//定义一个全局的网络接口

#if LWIP_DHCP
uint32_t g_dhcp_fine_timer = 0;					//DHCP精细处理计时器
__IO uint8_t g_lwip_dhcp_state = LWIP_DHCP_OFF; //DHCP状态初始化
#endif

/* LINK线程配置 */
#define LWIP_LINK_TASK_PRIO             3                   //任务优先级
#define LWIP_LINK_STK_SIZE              128 * 2             //任务堆栈大小
void lwip_link_thread( void * argument );                   //链路线程

/* DHCP线程配置 */
#define LWIP_DHCP_TASK_PRIO             4                   //任务优先级
#define LWIP_DHCP_STK_SIZE              128 * 2             //任务堆栈大小
void lwip_link_status_updated(struct netif *netif);
void lwip_dhcp_process(void *pvParameters);

/**
  * @breif	lwip 默认IP设置
  * @param	lwipx: lwip控制结构体指针
  * @retval	无
  */
void lwip_comm_default_ip_set(__lwip_dev *lwipx)
{
    //默认远端IP为:192.168.0.120
    lwipx->remoteip[0] = 192;
    lwipx->remoteip[1] = 168;
    lwipx->remoteip[2] = 0;
    lwipx->remoteip[3] = 120;
    //默认本地IP为:192.168.0.30
    lwipx->ip[0] = 192;
    lwipx->ip[1] = 168;
    lwipx->ip[2] = 1;
    lwipx->ip[3] = 30;
    //默认子网掩码:255.255.255.0
    lwipx->netmask[0] = 255;
    lwipx->netmask[1] = 255;
    lwipx->netmask[2] = 255;
    lwipx->netmask[3] = 0;
    //默认网关:192.168.0.1
    lwipx->gateway[0] = 192;
    lwipx->gateway[1] = 168;
    lwipx->gateway[2] = 1;
    lwipx->gateway[3] = 1;
	
    lwipx->dhcpstatus = 0;//没有DHCP
}

/**
  * @breif	LWIP初始化(LWIP启动的时候使用)
  * @param	无
  * @retval	0,成功
			1,内存错误
			2,以太网芯片初始化失败
			3,网卡添加失败.
  */
uint8_t LwIP_Init(void)
{
    struct netif *netif_init_flag;	//调用netif_add()函数时的返回值,用于判断网络初始化是否成功
    ip_addr_t ipaddr;				//ip地址
    ip_addr_t netmask;				//子网掩码
    ip_addr_t gw;					//默认网关
	if(ETH_BSP_Config())return 2;	//初始化LAN8720失败
	tcpip_init(NULL, NULL);			//初始化tcp ip内核,该函数里面会创建tcpip_thread内核任务
	lwip_comm_default_ip_set(&g_lwipdev);//设置默认IP等信息
    
#if LWIP_DHCP		//使用动态IP
	ipaddr.addr = 0;
	netmask.addr = 0;
	gw.addr = 0;
#else				//使用静态IP
	IP4_ADDR(&ipaddr,g_lwipdev.ip[0],g_lwipdev.ip[1],g_lwipdev.ip[2],g_lwipdev.ip[3]);
	IP4_ADDR(&netmask,g_lwipdev.netmask[0],g_lwipdev.netmask[1] ,g_lwipdev.netmask[2],g_lwipdev.netmask[3]);
	IP4_ADDR(&gw,g_lwipdev.gateway[0],g_lwipdev.gateway[1],g_lwipdev.gateway[2],g_lwipdev.gateway[3]);
	printf("静态IP地址........%d.%d.%d.%d\r\n",g_lwipdev.ip[0],g_lwipdev.ip[1],g_lwipdev.ip[2],g_lwipdev.ip[3]);
	printf("子网掩码..........%d.%d.%d.%d\r\n",g_lwipdev.netmask[0],g_lwipdev.netmask[1],g_lwipdev.netmask[2],g_lwipdev.netmask[3]);
	printf("默认网关..........%d.%d.%d.%d\r\n",g_lwipdev.gateway[0],g_lwipdev.gateway[1],g_lwipdev.gateway[2],g_lwipdev.gateway[3]);
#endif
	taskENTER_CRITICAL();//进入临界区
    netif_init_flag=netif_add(&g_lwip_netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, 
		(const ip_addr_t *)&gw, NULL, &ethernetif_init, &tcpip_input);//向网卡列表中添加一个网口
	taskEXIT_CRITICAL();//退出临界区

	if(netif_init_flag==NULL)return 3;//网卡添加失败 
    else//网口添加成功后,设置netif为默认值,并且打开netif网口
	{	
		netif_set_default(&g_lwip_netif);//设置netif为默认网口
        if (netif_is_link_up(&g_lwip_netif)) netif_set_up(&g_lwip_netif);//打开netif网口
        else netif_set_down(&g_lwip_netif);

#if LWIP_NETIF_LINK_CALLBACK
        lwip_link_status_updated(&g_lwip_netif);// DHCP链接状态更新函数
        netif_set_link_callback(&g_lwip_netif, lwip_link_status_updated);
		taskENTER_CRITICAL();//进入临界区
		sys_thread_new("eth_link",lwip_link_thread,&g_lwip_netif,
					LWIP_LINK_STK_SIZE,LWIP_LINK_TASK_PRIO);
		taskEXIT_CRITICAL();//退出临界区
#endif
	}
	g_lwipdev.link_status = LWIP_LINK_OFF;//链接标记为0 
#if LWIP_DHCP //如果使用DHCP的话
	g_lwipdev.dhcpstatus=0;	//DHCP标记为0
	taskENTER_CRITICAL();//进入临界区
	sys_thread_new("eth_dhcp",lwip_dhcp_process,&g_lwip_netif,
			LWIP_DHCP_STK_SIZE,LWIP_DHCP_TASK_PRIO);
	taskEXIT_CRITICAL();//退出临界区
#endif
	return 0;//操作OK.
}

/**
  * @brief	通知用户网络接口配置状态
  * @param	netif：网卡控制块
  */
void lwip_link_status_updated(struct netif *netif)
{
    if(netif_is_up(netif))
    {
#if LWIP_DHCP
        /* Update DHCP state machine */
        g_lwip_dhcp_state = LWIP_DHCP_START;
		printf ("The network cable is connected \r\n");
#endif /* LWIP_DHCP */
    }
    else
    {
#if LWIP_DHCP
        /* Update DHCP state machine */
        g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;
		printf ("The network cable is not connected \r\n");
#endif /* LWIP_DHCP */
    }
}

#if LWIP_DHCP       /* 如果使用DHCP */
/**
 * @brief	lwIP的DHCP分配进程
 * @param   pvParameters：网卡控制块
 */
void lwip_dhcp_process(void *pvParameters)
{
	struct netif *netif = (struct netif *) pvParameters;
    uint32_t ip = 0;
    uint32_t netmask = 0;
    uint32_t gw = 0;
    struct dhcp *dhcp;
    g_lwipdev.dhcpstatus = 1;//DHCP标记为1
    
	while(1)
	{
		switch (g_lwip_dhcp_state)//根据DHCP状态进入执行相应的动作
		{
			case LWIP_DHCP_START:{
				//对IP地址、网关地址及子网页码清零操作
				ip_addr_set_zero_ip4(&netif->ip_addr);
				ip_addr_set_zero_ip4(&netif->netmask);
				ip_addr_set_zero_ip4(&netif->gw);
				//设置DHCP的状态为等待分配IP地址
				g_lwip_dhcp_state = LWIP_DHCP_WAIT_ADDRESS;
				//开启DHCP
				dhcp_start(netif);
				printf("Looking for DHCP server,please wait...\r\n");
			}break;

			case LWIP_DHCP_WAIT_ADDRESS:{
				ip = g_lwip_netif.ip_addr.addr;       //读取新IP地址
				netmask = g_lwip_netif.netmask.addr;  //读取子网掩码
				gw = g_lwip_netif.gw.addr;            //读取默认网关
				if(dhcp_supplied_address(netif)) 
				{
					g_lwip_dhcp_state = LWIP_DHCP_ADDRESS_ASSIGNED;
					if (ip != 0)
					{
						taskENTER_CRITICAL();//进入临界区
						printf("DHCP分配成功......\r\n");
						g_lwipdev.dhcpstatus = 2;//DHCP成功
						//解析出通过DHCP获取到的IP地址 */
						g_lwipdev.ip[3] = (uint8_t)(ip >> 24);
						g_lwipdev.ip[2] = (uint8_t)(ip >> 16);
						g_lwipdev.ip[1] = (uint8_t)(ip >> 8);
						g_lwipdev.ip[0] = (uint8_t)(ip);
						printf("通过DHCP获取到IP地址......%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
						//解析通过DHCP获取到的子网掩码地址
						g_lwipdev.netmask[3] = (uint8_t)(netmask >> 24);
						g_lwipdev.netmask[2] = (uint8_t)(netmask >> 16);
						g_lwipdev.netmask[1] = (uint8_t)(netmask >> 8);
						g_lwipdev.netmask[0] = (uint8_t)(netmask);
						printf("通过DHCP获取到子网掩码....%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
						//解析出通过DHCP获取到的默认网关 
						g_lwipdev.gateway[3] = (uint8_t)(gw >> 24);
						g_lwipdev.gateway[2] = (uint8_t)(gw >> 16);
						g_lwipdev.gateway[1] = (uint8_t)(gw >> 8);
						g_lwipdev.gateway[0] = (uint8_t)(gw);
						printf("通过DHCP获取到的默认网关..%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
						
					}
					taskEXIT_CRITICAL();//退出临界区
				}
				else
				{
					dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
					if(dhcp->tries > LWIP_MAX_DHCP_TRIES)//DHCP超时
					{
						taskENTER_CRITICAL();//进入临界区
						printf ("DHCP分配失败，进入静态分配......\r\n");
						g_lwip_dhcp_state = LWIP_DHCP_TIMEOUT;
						//停止DHCP
						dhcp_stop(netif);
						g_lwipdev.dhcpstatus = 0XFF;
						//使用静态IP地址
						IP4_ADDR(&(g_lwip_netif.ip_addr), g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
						IP4_ADDR(&(g_lwip_netif.netmask), g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
						IP4_ADDR(&(g_lwip_netif.gw), g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
						netif_set_addr(netif, &g_lwip_netif.ip_addr, &g_lwip_netif.netmask, &g_lwip_netif.gw);
						printf("静态IP地址........%d.%d.%d.%d\r\n",g_lwipdev.ip[0],g_lwipdev.ip[1],g_lwipdev.ip[2],g_lwipdev.ip[3]);
						printf("子网掩码..........%d.%d.%d.%d\r\n",g_lwipdev.netmask[0],g_lwipdev.netmask[1],g_lwipdev.netmask[2],g_lwipdev.netmask[3]);
						printf("默认网关..........%d.%d.%d.%d\r\n",g_lwipdev.gateway[0],g_lwipdev.gateway[1],g_lwipdev.gateway[2],g_lwipdev.gateway[3]);
						taskEXIT_CRITICAL();//退出临界区
					}
				}
			}break;
			
			case LWIP_DHCP_LINK_DOWN:{
				dhcp_stop(netif);//停止DHCP
				g_lwip_dhcp_state = LWIP_DHCP_OFF;
			}break;
			
			default: break;
		}
		
		vTaskDelay(1000);//wait 1000 ms
	}
}
#endif

#if LWIP_NETIF_LINK_CALLBACK
/**
  * @brief       检查ETH链路状态，更新netif
  * @param       argument: netif
  * @retval      无
  */
void lwip_link_thread( void * argument )
{
    uint32_t regval = 0;
    struct netif *netif = (struct netif *) argument;
    int link_again_num = 0;

    while(1)
    {
        //读取PHY状态寄存器，获取链接信息
        regval=ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS,PHY_BSR);

        //判断链接状态
        if((regval&PHY_LINKED_STATUS)==0)
        {
            g_lwipdev.link_status = LWIP_LINK_OFF;
            link_again_num++ ;
            if(link_again_num>=2)continue;//网线一段时间没有插入
            else//关闭虚拟网卡及以太网中断
            {
#if LWIP_DHCP //如果使用DHCP的话 
                g_lwip_dhcp_state = LWIP_DHCP_LINK_DOWN;
                dhcp_stop(netif);
#endif
                ETH_Stop();
                netif_set_down(netif);
                netif_set_link_down(netif);
            }
        }
        else  //网线插入检测
        {
            link_again_num = 0;
            if (g_lwipdev.link_status == LWIP_LINK_OFF)/* 开启以太网及虚拟网卡 */
            {
                g_lwipdev.link_status = LWIP_LINK_ON;
                ETH_Start();
                netif_set_up(netif);
                netif_set_link_up(netif);
            }
        }

        vTaskDelay(1000);//wait 1000 ms
    }
}
#endif

